import math
from collections import defaultdict
from operator import itemgetter
from tqdm import tqdm
import pandas as pd


def createDict(rates):
    user_dict = {}
    movie_dict = {}
    for i in rates:
        if i[0] in user_dict:
            user_dict[i[0]].append((i[1], i[2]))
        else:
            user_dict[i[0]] = [(i[1], i[2])]
        if i[1] in movie_dict:
            movie_dict[i[1]].append(i[0])
        else:
            movie_dict[i[1]] = [i[0]]
    user_txt = pd.Series(user_dict)
    # user_txt.to_csv('user_txt.csv')
    item_txt = pd.Series(movie_dict)
    # item_txt.to_csv('job_txt.csv')
    return user_dict, movie_dict


def itemCF(user_dict):
    N = dict()
    C = defaultdict(defaultdict)
    W = defaultdict(defaultdict)
    for key in tqdm(user_dict):
        for i in user_dict[key]:
            if i[0] not in N.keys():
                N[i[0]] = 0
            N[i[0]] += 1
            for j in user_dict[key]:
                if i[0] == j[0]:
                    continue
                if j[0] not in C[i[0]].keys():
                    C[i[0]][j[0]] = 0
                C[i[0]][j[0]] += 1
    with open('sim_result.csv', 'w') as f:
        for i, related_item in tqdm(C.items()):
            for j, cij in related_item.items():
                W[i][j] = cij / math.sqrt(N[i] * N[j])
                data = [str(i), str(j), str(W[i][j]), str(cij), str(N[i]), str(N[j])]
                f.write(','.join(data) + '\n')
    f.close()
    return W


def recommondation(user_id, user_dict, K, W):
    rank = defaultdict(int)
    l = list()
    for i, score in user_dict[user_id]:
        click_list = [i[0] for i in user_dict[user_id]]
        for j, wj in sorted(W[i].items(), key=itemgetter(1), reverse=True)[0:K]:
            if j in click_list:
                continue
            rank[j] += score * wj
    l = sorted(rank.items(), key=itemgetter(1), reverse=True)[0:10]
    return l


if __name__ == '__main__':
    ratings = pd.read_table('ratings.dat', header=None, names=['UserID', 'MovieID', 'Rating', 'Timestamp'], sep='::',
                            engine='python')
    users = pd.read_table('users.dat', header=None, names=['UserID', 'Gender', 'Age', 'Occupation', 'Zip-code'],
                          sep='::', engine='python')
    movies = pd.read_table('movies.dat', header=None, names=['MovieID', 'Title', 'Genres'], sep='::', engine='python')

    user_dict, movie_dict = createDict(ratings[['UserID', 'MovieID', 'Rating']].values)
    W = itemCF(user_dict)

    with open('rec_result.csv', 'w') as f:
        for user_id in user_dict.keys():
            l = recommondation(user_id, user_dict, 20, W)
            rec_list = ','.join([str(i[0]) for i in l])
            f.write(f'{user_id}\t{rec_list}\n')

    f.close()
